package abel.wlmr.model.unit;

import abel.util.HexString;
import abel.wlmr.model.WlmrBaseUnit;
import abel.wlmr.model.WlmrException;
import abel.wlmr.model.type.FlowPointC29Body;
import abel.wlmr.model.type.FlowUnitField;
import io.netty.buffer.ByteBuf;

/**
 * B.5.4.1.3.29 F405： 水表测量点基本参数
 * 水表测量点基本参数数据单元格式见表B.42。
 * 表B.42 水表测量点基本参数数据单元格式
 * 数据内容 数据格式 单 位 字节数
 * 公称直径 BIN 无 5
 * 最大流量 见附录 C.29 附录 H 5
 * 额定（常用）流量 见附录 C.29 附录 H 5
 * 最小流量 见附录 C.29 附录 H 5
 * 量程比 BIN 无 2
 * 注：量程比：最大流量比最小流量
 * 
 * @author Abel
 *
 */
public class Afn04F405Unit extends WlmrBaseUnit {

    private static final short FIXED_LEN = 5 + 5 + 5 + 5 + 2;

    private HexString diameter;

    private FlowPointC29Body<FlowUnitField> maxFlow = new FlowPointC29Body<>(new FlowUnitField());

    private FlowPointC29Body<FlowUnitField> midFlow = new FlowPointC29Body<>(new FlowUnitField());

    private FlowPointC29Body<FlowUnitField> minFlow = new FlowPointC29Body<>(new FlowUnitField());

    private int flowTimes;

    public Afn04F405Unit() {
        super();
    }

    public Afn04F405Unit(short guessedLen) {
        super(guessedLen);
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitPart#appendBuf(io.netty.buffer.ByteBuf)
     */
    @Override
    public ByteBuf appendBuf(ByteBuf buf) {
        if (diameter == null) {
            throw new IllegalArgumentException("diameter can't be null");
        }
        if (maxFlow == null) {
            throw new IllegalArgumentException("max flow can't be null");
        }
        if (midFlow == null) {
            throw new IllegalArgumentException("mid flow can't be null");
        }
        if (minFlow == null) {
            throw new IllegalArgumentException("min flow can't be null");
        }
        if (flowTimes < 1) {
            throw new IllegalArgumentException("flow times should be positive");
        }

        buf.writeBytes(diameter.getBs());
        maxFlow.appendBuf(buf);
        midFlow.appendBuf(buf);
        minFlow.appendBuf(buf);
        buf.writeShortLE(flowTimes);

        return buf;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitPart#parseBuf(io.netty.buffer.ByteBuf)
     */
    @Override
    public int parseBuf(ByteBuf buf) throws WlmrException {
        if (buf.readableBytes() < getGuessedLength()) {
            return -1;
        }
        if (getGuessedLength() < FIXED_LEN) {
            throw new WlmrException("not enough bytes for 04-F405");
        }

        diameter = new HexString(buf, 5);

        maxFlow.parseBuf(buf);
        midFlow.parseBuf(buf);
        minFlow.parseBuf(buf);

        flowTimes = buf.readUnsignedShortLE();
        if (flowTimes < 1) {
            throw new WlmrException("flow times should be positive");
        }

        return getGuessedLength();
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.AppUnitBody#getFinalLen()
     */
    @Override
    public short getFinalLen() {
        return FIXED_LEN;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.WlmrDataPart#getMinLength()
     */
    @Override
    public int getMinLength() {
        return FIXED_LEN;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("{diameter:%s, maxFlow:%s, midFlow:%s, minFlow:%s, flowTimes:%s}", diameter, maxFlow,
            midFlow, minFlow, flowTimes);
    }

    /**
     * @return the diameter
     */
    public HexString getDiameter() {
        return diameter;
    }

    /**
     * @param diameter
     *            the diameter to set
     */
    public void setDiameter(HexString diameter) {
        if (diameter == null) {
            throw new IllegalArgumentException("diameter can't be null");
        }
        this.diameter = diameter;
    }

    /**
     * @return the maxFlow
     */
    public FlowPointC29Body<FlowUnitField> getMaxFlow() {
        return maxFlow;
    }

    /**
     * @param maxFlow
     *            the maxFlow to set
     */
    public void setMaxFlow(FlowPointC29Body<FlowUnitField> maxFlow) {
        if (maxFlow == null) {
            throw new IllegalArgumentException("max flow can't be null");
        }
        this.maxFlow = maxFlow;
    }

    /**
     * @return the midFlow
     */
    public FlowPointC29Body<FlowUnitField> getMidFlow() {
        return midFlow;
    }

    /**
     * @param midFlow
     *            the midFlow to set
     */
    public void setMidFlow(FlowPointC29Body<FlowUnitField> midFlow) {
        if (midFlow == null) {
            throw new IllegalArgumentException("mid flow can't be null");
        }
        this.midFlow = midFlow;
    }

    /**
     * @return the minFlow
     */
    public FlowPointC29Body<FlowUnitField> getMinFlow() {
        return minFlow;
    }

    /**
     * @param minFlow
     *            the minFlow to set
     */
    public void setMinFlow(FlowPointC29Body<FlowUnitField> minFlow) {
        if (minFlow == null) {
            throw new IllegalArgumentException("min flow can't be null");
        }
        this.minFlow = minFlow;
    }

    /**
     * @return the flowTimes
     */
    public int getFlowTimes() {
        return flowTimes;
    }

    /**
     * @param flowTimes
     *            the flowTimes to set
     */
    public void setFlowTimes(int flowTimes) {
        if (flowTimes < 1) {
            throw new IllegalArgumentException("flow times should be positive");
        }
        this.flowTimes = flowTimes;
    }

}
